/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package iamutkarshtiwari.github.io.imageeditorsample.ability;

import iamutkarshtiwari.github.io.ananas.editimage.utils.LogUtils;
import iamutkarshtiwari.github.io.imageeditorsample.ResourceTable;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.Image;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.window.dialog.ToastDialog;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.configuration.DeviceCapability;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.Camera;
import ohos.media.camera.device.CameraConfig;
import ohos.media.camera.device.CameraStateCallback;
import ohos.media.camera.device.FrameConfig;
import ohos.media.camera.params.Metadata;
import ohos.media.image.ImageReceiver;
import ohos.media.image.ImageSource;
import ohos.media.image.common.ImageFormat;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

import java.io.*;
import java.util.Optional;

/**
 * 拍照界面
 */
public class TakePictureAbility extends BaseAbility {
    public static final String TAKE_PICTURE = "take_picture";

    private EventHandler cameraEventHandler;
    private static final String TAG = "TakePictureAbilitySlice";
    private SurfaceProvider cameraPreview;
    private Image imgPicture;
    private Camera cameraDevice;

    private String picturePath;
    // 定义生成图片文件名
    private final String pictureName = "picture_001.jpg";

    private DependentLayout picTake, picPreview;
    private String filePath;


    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_take_picture);

        getWindow().setTransparent(true);
        getWindow().setBackgroundColor(new RgbColor(0xffffffff));
        getWindow().setStatusBarColor(Color.getIntColor("#000000"));

        cameraEventHandler = new EventHandler(EventRunner.create("TakePictureAbilitySlice"));
        picturePath = getExternalCacheDir().getPath() + File.separator;
        LogUtils.loge(TAG, picturePath);

        picTake = (DependentLayout) findComponentById(ResourceTable.Id_pic_take);
        picPreview = (DependentLayout) findComponentById(ResourceTable.Id_pic_preview);
        Image picCose = (Image) findComponentById(ResourceTable.Id_pic_close);
        Image picSel = (Image) findComponentById(ResourceTable.Id_pic_sel);

        imgPicture = (Image) findComponentById(ResourceTable.Id_preview_picture);
        cameraPreview = (SurfaceProvider) findComponentById(ResourceTable.Id_camera_preview);

        cameraPreview.pinToZTop(false);
        cameraPreview.getSurfaceOps().get().addCallback(new SurfaceCallBack());

        findComponentById(ResourceTable.Id_btn_take_picture).setClickedListener(component -> capture());

        takePictureInit();

        findComponentById(ResourceTable.Id_tack_back).setClickedListener(component -> onBackPressed());

        picCose.setClickedListener(component -> {
            picTake.setVisibility(Component.VISIBLE);
            picPreview.setVisibility(Component.HIDE);
        });

        picSel.setClickedListener(component -> {
            Intent intent1 = new Intent();
            intent1.setParam(TAKE_PICTURE, filePath);
            setResult(0, intent1);

            terminateAbility();
        });


    }

    private class SurfaceCallBack implements SurfaceOps.Callback {

        @Override
        public void surfaceCreated(SurfaceOps surfaceOps) {
            openCamera();
        }

        @Override
        public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) {

        }

        @Override
        public void surfaceDestroyed(SurfaceOps surfaceOps) {

        }
    }

    private final class CameraStateCallbackImpl extends CameraStateCallback {

        private Surface previewSurface;

        @Override
        public void onCreated(Camera camera) {
            // 创建相机设备
            previewSurface = cameraPreview.getSurfaceOps().get().getSurface();

            CameraConfig.Builder cameraConfigBuilder = camera.getCameraConfigBuilder();
            if (cameraConfigBuilder == null) {
                LogUtils.loge(TAG, "onCreated cameraConfigBuilder is null");
                return;
            }
            // 配置预览的Surface
            cameraConfigBuilder.addSurface(previewSurface);
            // 配置拍照的Surface
            cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            try {
                // 相机设备配置
                camera.configure(cameraConfigBuilder.build());
            } catch (IllegalArgumentException e) {
                LogUtils.loge(TAG, "Argument Exception");
            } catch (IllegalStateException e) {
                LogUtils.loge(TAG, "State Exception");
            }
        }

        @Override
        public void onConfigured(Camera camera) {
            // 获取预览配置模板
            FrameConfig.Builder framePreviewConfigBuilder = camera.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PREVIEW);
            // 配置预览Surface
            framePreviewConfigBuilder.addSurface(previewSurface);
            framePreviewConfigBuilder.setAeMode(Metadata.AfMode.AF_MODE_CONTINUOUS, new Rect());
            // 启动循环帧捕获
            camera.triggerLoopingCapture(framePreviewConfigBuilder.build());

            cameraDevice = camera;
        }

        @Override
        public void onPartialConfigured(Camera camera) {
            // 当使用了addDeferredSurfaceSize配置了相机，会接到此回调
        }

        @Override
        public void onReleased(Camera camera) {
            // 释放相机设备
            if (camera != null) {
                camera.release();
                camera = null;
            }
        }
    }

    private void capture() {
        if (cameraDevice == null) {
            ToastDialog toastDialog = new ToastDialog(getContext());
            toastDialog.setText("获取相机失败");
            toastDialog.show();
            return;
        }
        // 获取拍照配置模板
        FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(Camera.FrameConfigType.FRAME_CONFIG_PICTURE);
        // 配置拍照Surface
        framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
        // 配置拍照其他参数
        framePictureConfigBuilder.setImageRotation(90);//270

        // 启动单帧捕获(拍照)
        cameraDevice.triggerSingleCapture(framePictureConfigBuilder.build());

    }

    /**
     * 打开相机
     */
    private void openCamera() {
        CameraKit cameraKit = CameraKit.getInstance(TakePictureAbility.this);
        if (cameraKit == null) {
            LogUtils.loge(TAG, "获取cameraKit失败");
            terminateAbility();
        }
        String[] cameraIds = cameraKit.getCameraIds();
        if (cameraIds == null) {
            LogUtils.loge(TAG, "cameraIds is null");
            terminateAbility();
        }
        String cameraId = null;
        int length = cameraIds.length;
        LogUtils.loge("camera  size is  " + length);
        if (length <= 0) {
            LogUtils.loge(TAG, "cameraIds size is 0");
            terminateAbility();
        } else {
            cameraId = cameraIds[0];
        }
        // 相机创建和相机运行时的回调
        CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl();
        cameraKit.createCamera(cameraId, cameraStateCallback, cameraEventHandler);
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    // 图像帧数据接收处理对象
    private ImageReceiver imageReceiver;
    // 拍照支持分辨率
    private Size pictureSize;

    // 单帧捕获生成图像回调Listener
    private final ImageReceiver.IImageArrivalListener imageArrivalListener = new ImageReceiver.IImageArrivalListener() {
        @Override
        public void onImageArrival(ImageReceiver imageReceiver) {
            File myFile = new File(picturePath, pictureName); // 创建图片文件
            ImageSaver imageSaver = new ImageSaver(imageReceiver.readNextImage(), myFile); // 创建一个读写线程任务用于保存图片
            cameraEventHandler.postTask(imageSaver); // 执行读写线程任务生成图片
        }
    };

    // 保存图片, 图片数据读写，及图像生成见run方法
    class ImageSaver implements Runnable {
        private final ohos.media.image.Image myImage;
        private final File myFile;

        ImageSaver(ohos.media.image.Image image, File file) {
            myImage = image;
            myFile = file;
        }

        @Override
        public void run() {
            ohos.media.image.Image.Component component = myImage.getComponent(ImageFormat.ComponentType.JPEG);
            byte[] bytes = new byte[component.remaining()];
            component.read(bytes);
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(myFile);
                output.write(bytes); // 写图像数据
                output.flush();
            } catch (IOException e) {
                LogUtils.loge(TAG, "save picture occur exception!" + e.getLocalizedMessage());
            } finally {
                myImage.release();
                if (output != null) {
                    try {
                        output.close(); // 关闭流
                    } catch (IOException e) {
                        LogUtils.loge(TAG, "image release occur exception!");
                    }
                }
            }

            ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
            sourceOptions.formatHint = "image/jpg";
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
            File myFile = new File(picturePath, pictureName);
            filePath = picturePath + pictureName;

            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream(myFile);
                ImageSource imageSource = ImageSource.create(fileInputStream, sourceOptions);

                getUITaskDispatcher().asyncDispatch(() -> {
                    picTake.setVisibility(Component.HIDE);
                    picPreview.setVisibility(Component.VISIBLE);
                    imgPicture.setPixelMap(Optional.ofNullable(imageSource.createPixelmap(decodingOptions)).get());
                });
            } catch (FileNotFoundException e) {
                LogUtils.loge(TAG, "FileNotFoundException   " + e.getLocalizedMessage());
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private void takePictureInit() {
        DeviceCapability device = getContext().getResourceManager().getDeviceCapability();
        // 创建ImageReceiver对象，注意creat函数中宽度要大于高度；5为最大支持的图像数，请根据实际设置。
        imageReceiver = ImageReceiver.create(device.width, device.height, ImageFormat.JPEG, 1);
        imageReceiver.setImageArrivalListener(imageArrivalListener);
    }

}

